//lzw.cpp
#include "lzw.h"

#include <math.h>
#include "vector.h"
#include "bitStream.h"
LZW::LZW()
{
	hTable.initTable(32000); //TODO оч много. сделать можножным задавать из arch.cpp
	sTable.initTable(32000);
	oldCode=-1;
}
int LZW::compress(FILE* fileIn, FILE* fileOut)
{
	
	BitStream bitFileOut, bitFileIn;
	if((bitFileOut.open(fileOut, 'w'))==0)
		return 0;	
	if((bitFileIn.open(fileIn, 'r'))==0)
		return 0;	
	
	long nonmatch, lastsymbolcode, tableIndex;
	Vector vecBuff;
	int tempybuffcount=0;

	unchar readnByte;
	int buff=1;

	for(;;)
	{
		    buff=bitFileIn.get(8);			
		    if(buff==-1) 
		    	break;
		    readnByte=buff;
	
			if(!tempybuffcount)
				vecBuff.set(&readnByte, 1);
			else
				vecBuff.add(&readnByte, 1);
			++tempybuffcount;			

			nonmatch=1;

			tableIndex=hTable.search(vecBuff.getValues(), vecBuff.getSize());
			if(tableIndex!=(-1))
			{
					lastsymbolcode=tableIndex;
					nonmatch=0;
					continue;
			}
			if(nonmatch)
			{
				hTable.add(vecBuff.getValues(), vecBuff.getSize());
				bitFileOut.put(lastsymbolcode, hTable.howManyBitsToWrite());
				if((hTable.contCounter()>>hTable.howManyBitsToWrite())>0)
					hTable.incBitsToWrite();
				vecBuff.set(&readnByte, 1);
				tempybuffcount=1;
				tableIndex=hTable.search(vecBuff.getValues(), vecBuff.getSize());
				if(tableIndex!=(-1))
				{
					lastsymbolcode=tableIndex;
					continue;
				}

			}
	}
	hTable.add(vecBuff.getValues(), vecBuff.getSize());
	bitFileOut.put(lastsymbolcode, hTable.howManyBitsToWrite());
	bitFileOut.put(ENDOFFILE, hTable.howManyBitsToWrite());  //bytes EOF
//hTable.saveTable(); //!!!!!!!!!!!!
	return 1;
}
int LZW::decompress(FILE* fileIn, FILE* fileOut)
{
	Vector vecBuff;
			
	long bytescombination=0;
	unsigned long bytesReadn=0;

	BitStream bitFileOut, bitFileIn;
	if((bitFileOut.open(fileOut, 'w'))==0)
		return 0;	
	if((bitFileIn.open(fileIn, 'r'))==0)
		return 0;	
		
	for(;;)
	{
		++bytesReadn;
		bytescombination=bitFileIn.get((int)log2(sTable.getCount()+1)+1);
		if(bytescombination==ENDOFFILE)
			break;
		if(bytescombination>=sTable.getExCount())
		{
			vecBuff.set(sTable.getList(oldCode));
			vecBuff.add(&sTable.getList(oldCode)->getValues()[0],1);
			bitFileOut.put(vecBuff.getValues(), vecBuff.getSize());
			sTable.add(vecBuff.getValues(), vecBuff.getSize());		
			oldCode=bytescombination;
		}
		else
		{

			bitFileOut.put(sTable.getList(bytescombination)->getValues(), sTable.getList(bytescombination)->getSize());
			if(oldCode!=-1)
			{
				vecBuff.set(sTable.getList(oldCode));
				vecBuff.add(&sTable.getList(bytescombination)->getValues()[0],1);
				sTable.add(vecBuff.getValues(), vecBuff.getSize());
			}
			oldCode=bytescombination;
		}
	}
//sTable.saveTable(); //!!!!!!!!!!!!
	return 1;
}
void LZW::clear()
{
	hTable.clear();
	sTable.clear();
	oldCode=-1;
}
